#pragma once

#include <config.h>

BEGIN_NAMESPACE_OXGE

class Referenced
{

public:

	inline Referenced(){ _refCount=0;}

	inline Referenced(const Referenced&){_refCount=0;}

	inline Referenced& operator = (const Referenced&) { return *this; }

	
	/** Increment the reference count by one, indicating that 
	this object has another pointer which is referencing it.*/
	inline void ref() const{++_refCount;}

	/** Decrement the reference count by one, indicating that 
	a pointer to this object is referencing it.  If the
	reference count goes to zero, it is assumed that this object
	is no longer referenced and is automatically deleted.*/
	inline void unref() const{
		--_refCount;
		if(_refCount<1)delete this;	
	}

	/** Decrement the reference count by one, indicating that 
	a pointer to this object is referencing it.  However, do
	not delete it, even if ref count goes to 0.  Warning, unref_nodelete() 
	should only be called if the user knows exactly who will
	be responsible for, one should prefer unref() over unref_nodelete() 
	as the later can lead to memory leaks.*/
	inline void unref_nodelete() const{--_refCount;}

	/** Return the number pointers currently referencing this object. */
	inline int referenceCount() const { return _refCount; }


	//interface for boost intrusive ptr
	inline void intrusive_ptr_add_ref(){ ref(); }
	inline void intrusive_ptr_release(){ unref(); }
public:
	


protected:
	inline virtual ~Referenced(){}

	mutable int   _refCount;

};

//ref point 
template<class T>
class ref_ptr
{

public:
	typedef T element_type;

	ref_ptr() :_ptr(0L) {}
	ref_ptr(T* t):_ptr(t)              { if (_ptr) _ptr->ref(); }
	ref_ptr(const ref_ptr& rp):_ptr(rp._ptr)  { if (_ptr) _ptr->ref(); }
	~ref_ptr()                           { if (_ptr) _ptr->unref(); _ptr=0; }

	inline ref_ptr& operator = (const ref_ptr& rp)
	{
		if (_ptr==rp._ptr) return *this;
		T* tmp_ptr = _ptr;
		_ptr = rp._ptr;
		if (_ptr) _ptr->ref();
		// unref second to prevent any deletion of any object which might
		// be referenced by the other object. i.e rp is child of the
		// original _ptr.
		if (tmp_ptr) tmp_ptr->unref();
		return *this;
	}

	inline ref_ptr& operator = (T* ptr)
	{
		if (_ptr==ptr) return *this;
		T* tmp_ptr = _ptr;
		_ptr = ptr;
		if (_ptr) _ptr->ref();
		// unref second to prevent any deletion of any object which might
		// be referenced by the other object. i.e rp is child of the
		// original _ptr.
		if (tmp_ptr) tmp_ptr->unref();
		return *this;
	}

	// comparison operators for ref_ptr.
	inline bool operator == (const ref_ptr& rp) const { return (_ptr==rp._ptr); }
	inline bool operator != (const ref_ptr& rp) const { return (_ptr!=rp._ptr); }
	inline bool operator < (const ref_ptr& rp) const { return (_ptr<rp._ptr); }
	inline bool operator > (const ref_ptr& rp) const { return (_ptr>rp._ptr); }

	// comparison operator for const T*.
	inline bool operator == (const T* ptr) const { return (_ptr==ptr); }
	inline bool operator != (const T* ptr) const { return (_ptr!=ptr); }
	inline bool operator < (const T* ptr) const { return (_ptr<ptr); }
	inline bool operator > (const T* ptr) const { return (_ptr>ptr); }


	inline T& operator*()  { return *_ptr; }

	inline const T& operator*() const { return *_ptr; }

	inline T* operator->() { return _ptr; }

	inline const T* operator->() const   { return _ptr; }

	inline bool operator!() const   { return _ptr==0L; }

	inline bool valid() const       { return _ptr!=0L; }

	inline T* get() { return _ptr; }

	inline const T* get() const { return _ptr; }

	/** take control over the object pointed to by ref_ptr, unreferenced but do not delete even if ref count goes to 0,
	* return the pointer to the object.
	* Note, do not use this unless you are 100% sure your code handles the deletion of the object correctly, and
	* only use when absolutely required.*/
	inline T* take() { return release();}

	inline T* release() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp;}

private:
	T* _ptr;
};

END_NAMESPACE_OXGE
//
